home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / kernel / ptrace.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  5.6 KB  |  222 lines

  1. /*
  2.  * ptrace.c
  3.  * By Ross Biro 1/23/92
  4.  * edited by Linus Torvalds
  5.  *
  6.  * This file is subject to the terms and conditions of the GNU General Public
  7.  * License.  See the file README.legal in the main directory of this archive
  8.  * for more details.
  9.  */
  10.  
  11. #include <linux/head.h>
  12. #include <linux/kernel.h>
  13. #include <linux/sched.h>
  14. #include <linux/mm.h>
  15. #include <linux/errno.h>
  16. #include <linux/ptrace.h>
  17. #include <linux/user.h>
  18.  
  19. #include <asm/segment.h>
  20. #include <asm/system.h>
  21. #include <linux/debugreg.h>
  22.  
  23. /*
  24.  * does not yet catch signals sent when the child dies.
  25.  * in exit.c or in signal.c.
  26.  */
  27.  
  28. /* change a pid into a task struct. */
  29. static inline struct task_struct * get_task(int pid)
  30. {
  31.     int i;
  32.  
  33.     for (i = 1; i < NR_TASKS; i++) {
  34.         if (task[i] != NULL && (task[i]->pid == pid))
  35.             return task[i];
  36.     }
  37.     return NULL;
  38. }
  39.  
  40. /*
  41.  * this routine will get a word off of the processes priviledged stack.
  42.  * the offset is how far from the base addr as stored in the TSS.
  43.  * this routine assumes that all the priviledged stacks are in our
  44.  * data space.
  45.  */
  46. int ptrace_get_stack_long(struct task_struct *task, int offset)
  47. {
  48.     unsigned char *stack;
  49.  
  50.     stack = (unsigned char *)task->tss.esp0;
  51.     stack += offset;
  52.     return (*((int *)stack));
  53. }
  54.  
  55. /*
  56.  * this routine will put a word on the processes priviledged stack.
  57.  * the offset is how far from the base addr as stored in the TSS.
  58.  * this routine assumes that all the priviledged stacks are in our
  59.  * data space.
  60.  */
  61. int ptrace_put_stack_long(struct task_struct *task, int offset,
  62.               unsigned long data)
  63. {
  64.     unsigned char * stack;
  65.     
  66.     stack = (unsigned char *) task->tss.esp0;
  67.     stack += offset;
  68.     *(unsigned long *) stack = data;
  69.     return 0;
  70. }
  71.  
  72. asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
  73. {
  74.     struct task_struct *child;
  75.  
  76.     if (request == PTRACE_TRACEME) {
  77.         /* are we already being traced? */
  78.         if (current->flags & PF_PTRACED)
  79.             return -EPERM;
  80.         /* set the ptrace bit in the proccess flags. */
  81.         current->flags |= PF_PTRACED;
  82.         return 0;
  83.     }
  84.     if (pid == 1)           /* you may not mess with init */
  85.         return -EPERM;
  86.     if (!(child = get_task(pid)))
  87.         return -ESRCH;
  88.     if (request == PTRACE_ATTACH) {
  89.         if (child == current)
  90.             return -EPERM;
  91.         if ((!child->dumpable || (current->uid != child->euid) ||
  92.             (current->gid != child->egid)) && !suser())
  93.             return -EPERM;
  94.         /* the same process cannot be attached many times */
  95.         if (child->flags & PF_PTRACED)
  96.             return -EPERM;
  97.         child->flags |= PF_PTRACED;
  98.         if (child->p_pptr != current) {
  99.             REMOVE_LINKS(child);
  100.             child->p_pptr = current;
  101.             SET_LINKS(child);
  102.         }
  103.         send_sig(SIGSTOP, child, 1);
  104.         return 0;
  105.     }
  106.     if (!(child->flags & PF_PTRACED))
  107.         return -ESRCH;
  108.     if (child->state != TASK_STOPPED) {
  109.         if (request != PTRACE_KILL && request != PTRACE_DETACH)
  110.             return -ESRCH;
  111.     }
  112.     if (child->p_pptr != current)
  113.         return -ESRCH;
  114.  
  115.     switch (request) {
  116.     /* when I and D space are seperate, these will need to be fixed. */
  117.         case PTRACE_PEEKTEXT: /* read word at location addr. */
  118.         case PTRACE_PEEKDATA: {
  119.             unsigned long tmp;
  120.             int res;
  121.  
  122.             res = ptrace_read_long(child, addr, &tmp);
  123.             if (res < 0)
  124.                 return res;
  125.             res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
  126.             if (!res)
  127.                 put_fs_long(tmp,(unsigned long *) data);
  128.             return res;
  129.         }
  130.  
  131.     /* read the word at location addr in the USER area. */
  132.         case PTRACE_PEEKUSR:
  133.             return ptrace_peekusr (child, addr, data);
  134.  
  135.       /* when I and D space are seperate, this will have to be fixed. */
  136.         case PTRACE_POKETEXT: /* write the word at location addr. */
  137.         case PTRACE_POKEDATA:
  138.             return ptrace_write_long(child,addr,data);
  139.  
  140.         case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
  141.             return ptrace_pokeusr (child, addr, data);
  142.  
  143.         case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
  144.         case PTRACE_CONT: { /* restart after signal. */
  145.             if ((unsigned long) data > NSIG)
  146.                 return -EIO;
  147.             if (request == PTRACE_SYSCALL)
  148.                 child->flags |= PF_TRACESYS;
  149.             else
  150.                 child->flags &= ~PF_TRACESYS;
  151.             child->exit_code = data;
  152.             child->state = TASK_RUNNING;
  153.     /* make sure the single step bit is not set. */
  154.             ptrace_clrsingle(child);
  155.             return 0;
  156.         }
  157.  
  158. /*
  159.  * make the child exit.  Best I can do is send it a sigkill.
  160.  * perhaps it should be put in the status that it want's to
  161.  * exit.
  162.  */
  163.         case PTRACE_KILL: {
  164.             child->state = TASK_RUNNING;
  165.             child->exit_code = SIGKILL;
  166.     /* make sure the single step bit is not set. */
  167.             ptrace_clrsingle (child);
  168.             return 0;
  169.         }
  170.  
  171.         case PTRACE_SINGLESTEP: {  /* set the trap flag. */
  172.             if ((unsigned long) data > NSIG)
  173.                 return -EIO;
  174.             child->flags &= ~PF_TRACESYS;
  175.             ptrace_setsingle (child);
  176.             child->state = TASK_RUNNING;
  177.             child->exit_code = data;
  178.     /* give it a chance to run. */
  179.             return 0;
  180.         }
  181.  
  182.         case PTRACE_DETACH: { /* detach a process that was attached. */
  183.             if ((unsigned long) data > NSIG)
  184.                 return -EIO;
  185.             child->flags &= ~(PF_PTRACED|PF_TRACESYS);
  186.             child->state = TASK_RUNNING;
  187.             child->exit_code = data;
  188.             REMOVE_LINKS(child);
  189.             child->p_pptr = child->p_opptr;
  190.             SET_LINKS(child);
  191.             /* make sure the single step bit is not set. */
  192.             ptrace_clrsingle(child);
  193.             return 0;
  194.         }
  195.  
  196.         default:
  197.             return -EIO;
  198.     }
  199.     return -EIO;
  200. }
  201.  
  202.  
  203. asmlinkage void syscall_trace(void)
  204. {
  205.     if ((current->flags & (PF_PTRACED|PF_TRACESYS))
  206.             != (PF_PTRACED|PF_TRACESYS))
  207.         return;
  208.     current->exit_code = SIGTRAP;
  209.     current->state = TASK_STOPPED;
  210.     notify_parent(current);
  211.     schedule();
  212.     /*
  213.      * this isn't the same as continuing with a signal, but it will do
  214.      * for normal use.  strace only continues with a signal if the
  215.      * stopping signal is not SIGTRAP.  -brl
  216.      */
  217.     if (current->exit_code)
  218.         current->signal |= (1 << (current->exit_code - 1));
  219.     current->exit_code = 0;
  220.     return;
  221. }
  222.